"""
项目常用工具函数
"""
import http
import json
import os
import random

from hashlib import md5
from io import StringIO, BytesIO
from urllib.error import URLError
from urllib.parse import urlencode

import celery
import qrcode
import requests
from celery.schedules import crontab
from django.conf import settings
from django.core.cache import caches
from django_redis import get_redis_connection
from qiniu import Auth, put_file, put_stream


def get_ip_address(request):
    """获得请求的IP地址"""
    ip = request.META.get('HTTP_X_FORWARDED_FOR', None)
    return ip or request.META['REMOTE_ADDR']


def to_md5_hex(origin_str):
    """生成MD5摘要"""
    return md5(origin_str.encode('utf-8')).hexdigest()


def gen_mobile_code(length=6):
    """生成指定长度的手机验证码"""
    code = StringIO()
    for _ in range(length):
        code.write(str(random.randint(0, 9)))
    return code.getvalue()


ALL_CHARS = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'


def gen_captcha_text(length=4):
    """生成指定长度的图片验证码文字"""
    code = StringIO()
    chars_len = len(ALL_CHARS)
    for _ in range(length):
        index = random.randrange(chars_len)
        code.write(ALL_CHARS[index])
    return code.getvalue()


def gen_qrcode(data):
    """生成二维码"""
    image = qrcode.make(data)
    buffer = BytesIO()
    image.save(buffer)
    return buffer.getvalue()


SMS_SERVER = '106.ihuyi.com'
SMS_URL = '/webservice/sms.php?method=Submit'
SMS_ACCOUNT = 'C38434632'
SMS_PASSWORD = '621c711b9840d5e7a75143c3c3b5e23f'
MSG_TEMPLATE = '您的验证码是：%s。请不要把验证码泄露给其他人。'


def send_sms_by_ihuyi(tel, code):
    """发送短信（调用互亿无线短信网关）"""
    params = urlencode({
        'account': SMS_ACCOUNT,
        'password': SMS_PASSWORD,
        'content': MSG_TEMPLATE % code,
        'mobile': tel,
        'format': 'json'
    })
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Accept': 'text/plain'
    }
    conn = http.client.HTTPConnection(SMS_SERVER, port=80, timeout=10)
    try:
        conn.request('POST', SMS_URL, params, headers)
        caches['default'].set(f'mobile_code:{tel}', code, timeout=120)
        return conn.getresponse().read().decode('utf-8')
    except URLError or KeyError as e:
        return json.dumps({
            'code': 500,
            'msg': '短信服务暂时无法使用'
        })
    finally:
        conn.close()


# 注册环境变量（注册Django配置文件）
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'fangtx.settings')
# 创建Celery的实例 - broker代表消息代理（从哪里获取消息队列服务）
app = celery.Celery('common.utils',
                    broker='redis://:1qaz2wsx@120.77.222.217:6379/0')
# 读取Django项目的配置信息
app.config_from_object('django.conf:settings')
# celery -A common.utils worker -l info &
# 使用Windows 10做开发且使用celery 4.x版本需要先安装一个三方库作为辅助
# pip install eventlet
# 然后启动celery的消费者的时候需要多加一个参数
# celery -A common.utils worker -l info -P eventlet


# 用app.task装饰需要异步执行的函数（注册异步函数）
@app.task
def send_sms_by_luosimao(tel, code):
    """发送短信验证码（调用螺丝帽短信网关）"""
    resp = requests.post(
        url='http://sms-api.luosimao.com/v1/send.json',
        auth=('api', 'key-524049379b633f7a4344494e95b09f89'),
        data={
            'mobile': tel,
            'message': f'您的验证码为{code}。【铁壳测试】'
        },
        timeout=10,
        verify=False)
    # Django框架封装好的缓存调用方式（简单但是弱小）
    # caches['default'].set(f'mobile_code:{tel}', code, timeout=120)
    # 可以通过django_redis的函数获得原生的Redis连接进行操作（强大）
    cli = get_redis_connection(alias='default')
    cli.set(f'mobile_code:{tel}', code, ex=120)
    return resp.content


QINIU_ACCESS_KEY = 'KarvlHfUdoG1mZNSfDVS5Vh3nae2jUZumTBHK-PR'
QINIU_SECRET_KEY = 'SFPFkAn5NENhdCMqMe9wd_lxGHAeFR5caXxPTtt7'
QINIU_BUCKET_NAME = 'jackfrued'

auth = Auth(QINIU_ACCESS_KEY, QINIU_SECRET_KEY)


@app.task
def upload_filepath_to_qiniu(file_path, filename):
    """将文件上传到七牛云存储"""
    token = auth.upload_token(QINIU_BUCKET_NAME, filename)
    ret, info = put_file(token, filename, file_path)


@app.task
def upload_stream_to_qiniu(file_stream, filename, size):
    """将文件上传到七牛云存储"""
    token = auth.upload_token(QINIU_BUCKET_NAME, filename)
    ret, info = put_stream(token, filename, file_stream, None, size)


@app.task
def show_message(content):
    print(content)


app.conf.update(
    timezone=settings.TIME_ZONE,
    enable_utc=True,
    # 定时任务要通过消息的生产者将其转换成队列中的消息
    # celery -A common.utils beat -l info
    beat_schedule={
        'task_one': {
            'task': 'common.utils.show_message',
            'schedule': crontab(),
            'args': ('刘强东，奶茶妹妹喊你回家喝奶啦', )
        },
    },
)
